【FreeRTOS】详细讲解FreeRTOS中事件(event)并通过具体示例讲述其用法 |
您所在的位置:网站首页 › freertos 调度 › 【FreeRTOS】详细讲解FreeRTOS中事件(event)并通过具体示例讲述其用法 |
文章目录
事件函数解析示例
事件
事件,实际上是一种任务间通信的机制,主要用于实现多任务间的同步,其只能是事件类型的通信,无数据传输。与信号量不同的是,它可以实现一对多,多对多的同步。即可以是任意一个事件发生时唤醒任务进行事件处理;也可以是几个事件都发生后才唤醒任务进行事件处理;同样,也可以是多个任务同步多个事件。 FreeRTOS中任务可以通过设置事件位来实现事件的触发和等待操作。但FreeRTOS的事件仅用于同步,不提供数据传输功能,其具有如下特点: 事件只与任务相关联,事件相互独立,一个32位的事件集合(EventBits_t类型的变量,实际可用与表示事件的只有24位),用于标识该任务发生的事件类型,其中每一位表示一种事件类型(0表示该事件类型未发生、1表示该事件类型已经发生),一共24种事件类型;事件仅用于同步,不提供数据传输功能;事件无排队性,即多次向任务设置同一事件(如果任务还未来得及读走),等效于只设置一次;允许多任务对同一事件进行读写操作;支持事件等待超时机制。应用 事件在一定程度上可以代替信号量,用于任务与任务间、中断与任务间同步。 与信号量不同之处在于,事件是不可累计的,而信号量是可累计。并且,一个任务使用事件同步时,可以等待多个事件产生才进行同步;而信号量是单一的同步操作,只能与一个中断或任务同步,无法与多个中断或任务同步。 事件运行机制示意图实际使用事件相关函数前,需要将configSUPPORT DYNAMIC ALLOCATION置1。 函数解析前奏 定义事件控制权柄所用的EventGroupHandle_t其实是一个结构体指针,其声明为typedef struct EventGroupDef_t * EventGroupHandle_t。事件控制块EventGroup_t,内部最多含有四个变量,其中两个变量uxEventBits与xTasksWaitingForBits是一直可使用,但变量uxEventGroupNumber与ucStaticallyAllocated收到FreeRTOS配置管理 typedef struct EventGroupDef_t { EventBits_t uxEventBits; List_t xTasksWaitingForBits; #if ( configUSE_TRACE_FACILITY == 1 ) UBaseType_t uxEventGroupNumber; #endif #if ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) \ && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) uint8_t ucStaticallyAllocated; #endif } EventGroup_t;EventBits_t:事件标志组存储在EventBits_t 类型的变量中。 若FreeRTOS配置时,将configUSE_16_BIT_TICKS定义为1,那么EventBits_t就为16位,其中只有8位存储时间组;否则,若configUSE_16_BIT_TICKS定义为0,那么EventBits_t就为32位,其中24位存储事件组。每一位代表一个事件是否发生(事件发生为1,否则为0)。倘若兄弟认为8位或24位事件组不够用,还可以使用与或非等逻辑运算来组成更多事件。🤣🤣🤣 xTasksWaitingForBits:该变量是一个列表,内部存储等待此事件的所有任务。 uxEventGroupNumber:记录事件组数量。 ucStaticallyAllocated:记录时间组分配方式,如果事件组是静态分配的,则设置为 pdTRUE,以确保不尝试释放内存。 动态创建事件 原函数 EventGroupHandle_t xEventGroupCreate( void );参数解析 返回值:类型为EventGroupHandle_t,其为事件的控制权柄。函数说明 动态创建一个事件。 静态创建事件 原函数 EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t * pxEventGroupBuffer );参数解析 StaticEventGroup_t * pxEventGroupBuffer:为事件组分配的空间;返回值:类型为EventGroupHandle_t,其为事件的控制权柄函数说明 静态创建事件组,创建时需要传入存储空间。 创建事件 原函数 void vEventGroupDelete( EventGroupHandle_t xEventGroup );参数解析 EventGroupHandle_t xEventGroup:传入事件组控制权柄;函数说明 &esnp;删除事件组,只要将事件组控制权柄传入即可。删除只能删除已经创建成功的事件组。 事件触发 原函数 EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );参数解析 EventGroupHandle_t xEventGroup:事件组的控制权柄;const EventBits_t uxBitsToSet:需要触发事件的,也就是其在事件组的位置;返回值:返回函数操作的事件组的值;函数说明 触发事件组中某个事件(事件对应事件组的位置),其位置由uxBitsToSet的值决定。 该函数内部有判断机制,即的判断该事件是否创建,只有事件组创建成功以及操作位有效,该函数才能正常运作。 中断中唤醒事件 原函数 BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t * pxHigherPriorityTaskWoken );参数解析 EventGroupHandle_t xEventGroup:事件组的操作句柄;const EventBits_t uxBitsToSet:需要触发事件的,也就是其在事件组的位置;BaseType_t * pxHigherPriorityTaskWoken:在使用之前必须初始化成pdFALSE;返回值:类型为BaseType_t。若其值为pdFalse,则消息已经发送成功;否则,发送失败。函数说明 是xEventGroupSetBits函数的中断版,其功能是中断中唤醒某个事件。 等待事件唤醒 原函数 EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait );参数解析 EventGroupHandle_t xEventGroup:事件的操作句柄;const EventBits_t uxBitsToWaitFor:等待的事件,这里可以是多个事件,使用或运算即可连接;const BaseType_t xClearOnExit:当其值为pdTRUE时,一旦监测到匹配的事件,系统就会将删除由该事件引起的标志位;否则,当其值为pdFALSE时,将删除标志位;const BaseType_t xWaitForAllBits:当其值为pdTURE时,相应的uxBitsToWaitFor中多个事件应该使用&连接;否则当其值为pdFALSE时,uxBitsToWaitFor中多个事件应该使用|连接。这样函数返回值才是对应标志位的值,事件才能够触发。TickType_t xTicksToWait:最大超时时间,单位为系统节拍时间,使用portMAX_DELAY即相当于一直阻塞;返回值:类型为EventBits_t,返回事件中事件标志位,但是返回值很可能并不是用户指定的事件位,需要再进行判断再处理。函数说明 xEventGroupWaitBits函数的作用是等待事件触发。若需要等待的事件一直未触发,函数就会阻塞,阻塞时间为最大超时时间xTicksToWait。 清除事件标志位 原函数 EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear );参数解析 EventGroupHandle_t xEventGroup:事件组操作句柄;const EventBits_t uxBitsToClear:时间组中需要清除的位置;返回值:类型EventBits_t,返回事件清除前的值;函数说明 清除事件组中对应位置的标志位。在获取事件时对应标志位未擦除,那么可以使用该函数做显示擦除。 中断中清除事件标志位 原函数 BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );参数解析 EventGroupHandle_t xEventGroup:事件组操作句柄;const EventBits_t uxBitsToClear:时间组中需要清除的位置;返回值:类型EventBits_t,返回事件清除前的值;函数说明 是函数xEventGroupClearBits的中断版,功能上与之一样。 示例声明8个事件,并且创建一个FreeRTOS事件,用于任务同步,再创建两个任务。完成:任务1,等待事件触发,7个事件中触发一个事件后反转对应LED的状态,当事件8触发时,统计其触发次数并且显示到LCD屏上; 任务2,每个1s发送一个事件触发请求,并且反转LED8的状态。 核心源码 //任务控制权柄 TaskHandle_t xHandleTsak[2]; // 事件控制权柄 EventGroupHandle_t myxEventGroupHandle_t = NULL; // 声明事件 #define EVENT1 (0x01 // 设置变量接收事件 EventBits_t r_event; // 保存LED的状态 int ledState[] = {0,0,0,0,0,0,0}; // 记录LED的位置 uint16_t ledLocation[] = {LED1,LED2,LED3,LED4,LED5,LED6,LED7}; // 记录EVENT8触发次数 uint16_t eventTriggerCount = 0; // 保存显示到LCD中的数据 char temp[30]; // 用于循环 int i = 0; while(1) { //阻塞等待8个事件中任意一个事件 r_event = xEventGroupWaitBits(myxEventGroupHandle_t,EVENT1|EVENT2|EVENT3|EVENT4|EVENT5|EVENT6|EVENT7|EVENT8, pdTRUE,pdFALSE,portMAX_DELAY); //判断事件类型 if((r_event&EVENT1) !=0) ++ledState[0]; else if((r_event&EVENT2) !=0) ++ledState[1]; else if((r_event&EVENT3) !=0) ++ledState[2]; else if((r_event&EVENT4) !=0) ++ledState[3]; else if((r_event&EVENT5) !=0) ++ledState[4]; else if((r_event&EVENT6) !=0) ++ledState[5]; else if((r_event&EVENT7) !=0) ++ledState[6]; else { sprintf(temp," Event8 count:%d",++eventTriggerCount); LCD_DisplayStringLine(Line4,(uint8_t*)temp); changeAllLedByStateNumber(OFF); } // 设置每个LED灯状态 for(i=0;iEVENT1,EVENT2,EVENT3,EVENT4,EVENT5,EVENT6,EVENT7,EVENT8}; int i = -1; // 保存系统时间 static portTickType myPreviousWakeTime; // 保存阻塞时间 const volatile TickType_t xDelay1000ms = pdMS_TO_TICKS( 1000UL ); // 获取当前时间 myPreviousWakeTime = xTaskGetTickCount(); while(1) { // 每次执行都翻转LED8状态 以保证肉眼看到该任务在运行 rollbackLedByLocation(LED8); // 发送事件同步 xEventGroupSetBits(myxEventGroupHandle_t,event[++i%8]); // 非阻塞延时1s xTaskDelayUntil( &myPreviousWakeTime,xDelay1000ms ); } }结果 事件测试结果图小编也有其他的一些相关文章,欢迎各位看官点击观看😉😉😉 【FreeRTOS】详细讲解FreeRTOS中任务管理并通过示例讲述其用法【FreeRTOS】详细讲解FreeRTOS的软件定时器及通过示例讲述其用法【FreeRTOS】详细讲解FreeRTOS中消息队列并通过示例讲述其用法 最后 ,欢迎大家留言或私信交流,共同进步!😁😁😁 |
今日新闻 |
点击排行 |
|
推荐新闻 |
图片新闻 |
|
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭 |